#include <stdio.h>

int main1()
{
    char a[1000];
    char b;
    gets(a);
    b = getchar();
    printf("-----\n");
    printf("%s\n", a);
    printf("-----\n");
    printf("%c\n", b);
    printf("-----\n");
    int k = 0;
    char c = b;
    if (b >= 'a' && b <= 'z')
    {
        //先减后加否则会运算溢出
        c = (char)(b - 'a' + 'A');
    }
    else if (b >= 'A' && b <= 'Z')
    {
        //先减后加否则会运算溢出
        c = (char)(b - 'A' + 'a');
    }
    for (int i = 0; i < 1000; i++)
    {
        if (a[i] == '\0')
            break;
        if (a[i] == b || a[i] == c)
            k++;
    }
    printf("%d\n", k);
    return 0;
}

int main2()
{
    int d[1001];
    int a = 1, b = 0, i = 0;
    do
    {
        scanf("%n", &a);
        for (i = 0; i < a; i++)
        {
            scanf("%n", &b);
            d[b]++;
        }
    } while (a > 0);
    for (i = 1; i < 1001; i++)
    {
        if (d[i] > 0)
            printf("%n", i);
    }
    return 0;
}

//HJ6 质数因子
int main3()
{
    unsigned int a;
    scanf("%d", &a);
    for (unsigned int i = 2; i * i <= a && i <= a; i++)
    {
        while (a % i == 0)
        {
            printf("%d ", i);
            a = a / i;
        }
    }
    if (a != 1)
        printf("%d ", a);
    return 0;
}

//HJ89 24点运算
int main4()
{
    char strs[14][3] = {"\0", "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
    char num[4][6] = {"\0", "\0", "\0", "\0"};
    int v[4] = {0}, w[4] = {0};
    int i = 0;
    scanf("%s %s %s %s", num[0], num[1], num[2], num[3]);
    while (i < 4)
    {
        if (num[i][2] != '\0')
        {
            printf("ERROR");
            return 0;
        }
        switch (num[i][0])
        {
        case 'k':
        case 'K':
            v[i] = 13;
            break;
        case 'q':
        case 'Q':
            v[i] = 12;
            break;
        case 'j':
        case 'J':
            v[i] = 11;
            break;
        case '1':
            if (num[i][0] == '1' && num[i][1] != '0')
            {
                printf("ERROR");
                return 0;
            }
            v[i] = 10;
            break;
        case '9':
            v[i] = 9;
            break;
        case '8':
            v[i] = 8;
            break;
        case '7':
            v[i] = 7;
            break;
        case '6':
            v[i] = 6;
            break;
        case '5':
            v[i] = 5;
            break;
        case '4':
            v[i] = 4;
            break;
        case '3':
            v[i] = 3;
            break;
        case '2':
            v[i] = 2;
            break;
        case 'a':
        case 'A':
            v[i] = 1;
            break;
        default:
            printf("ERROR");
            return 0;
        }
        i++;
    }
    //printf("\nInt::\t%d,%d,%d,%d \n", v[0], v[1], v[2], v[3]);
    w[0] = v[0];
    w[1] = v[1];
    w[2] = v[2];
    w[3] = v[3];
    //定义算符标识：加-->0,乘-->1,减-->2,除-->3
    char op[4] = {'+', '*', '-', '/'};
    //生成所有的算符集合
    int ops[4 * 4 * 4][3];
    int t = 0;
    //从函数增长性考虑，上升性算符：+*，下降性算符：-/,起点：<=13,终点：>=24,去掉全部算符下降性算符的组合
    for (int j = 0; j < 4; j++)
    {
        for (int k = 0; k < 4; k++)
        {
            for (int l = 0; l < 4; l++)
            {
                if (j >= 2 && k >= 2 && l >= 2)
                    ops[t][0] = -1;
                else
                {
                    ops[t][0] = j;
                    ops[t][1] = k;
                    ops[t][2] = l;
                }
                t++;
            }
        }
    }
    for (int j = 0; j < 4; j++)
    {
        for (int k = 0; k < 4; k++)
        {
            if (k == j)
                continue;
            for (int l = 0; l < 4; l++)
            {
                if (l == j || l == k)
                    continue;
                w[0] = v[j];
                w[1] = v[k];
                w[2] = v[l];
                w[3] = v[6 - j - k - l];
                int r;
                for (int x = 0; x < 64; x++)
                {
                    //跳过全降算符
                    if (ops[x][0] == -1)
                        continue;
                    r = v[j];
                    t = 1;
                    for (i = 0; i < 3; i++)
                    {
                        if (ops[x][i] == 0)
                            r += w[t];
                        else if (ops[x][i] == 1)
                            r *= w[t];
                        else if (ops[x][i] == 2)
                            r -= w[t];
                        else if (ops[x][i] == 3)
                            r /= w[t];
                        t++;
                    }
                    if (r != 24)
                        continue;
                    printf("%s%c%s%c%s%c%s", strs[w[0]], op[ops[x][0]], strs[w[1]], op[ops[x][1]], strs[w[2]], op[ops[x][2]], strs[w[3]]);
                    return 0;
                }
            }
        }
    }
    printf("NONE");
    return 0;
}

// HJ18 识别有效的IP地址和掩码并进行分类统计
/*
请解析IP地址和对应的掩码，进行分类识别。要求按照A/B/C/D/E类地址归类，不合法的地址和掩码单独归类。
所有的IP地址划分为 A,B,C,D,E五类
A类地址1.0.0.0~126.255.255.255;
B类地址128.0.0.0~191.255.255.255;
C类地址192.0.0.0~223.255.255.255;
D类地址224.0.0.0~239.255.255.255；
E类地址240.0.0.0~255.255.255.255;


私网IP范围是：
10.0.0.0-10.255.255.255
172.16.0.0-172.31.255.255
192.168.0.0-192.168.255.255


子网掩码为二进制下前面是连续的1，然后全是0。（例如：255.255.255.32就是一个非法的掩码）
（注意二进制下全是1或者全是0均为非法子网掩码）

注意：
1. 类似于【0.*.*.*】和【127.*.*.*】的IP地址不属于上述输入的任意一类，也不属于不合法ip地址，计数时请忽略
2. 私有IP地址和A,B,C,D,E类地址是不冲突的

输入描述：
多行字符串。每行一个IP地址和掩码，用~隔开。

输出描述：
统计A、B、C、D、E、错误IP地址或错误掩码、私有IP的个数，之间以空格隔开。
*/
int main_IP()
{
    unsigned char ip_a[8] = {1, 0, 0, 0, 126, 255, 255, 255};
    unsigned char ip_b[8] = {128, 0, 0, 0, 191, 255, 255, 255};
    unsigned char ip_c[8] = {192, 0, 0, 0, 223, 255, 255, 255};
    unsigned char ip_d[8] = {224, 0, 0, 0, 239, 255, 255, 255};
    unsigned char ip_e[8] = {240, 0, 0, 0, 255, 255, 255, 255};
    unsigned char ip_p1[8] = {10, 0, 0, 0, 10, 255, 255, 255};
    unsigned char ip_p2[8] = {172, 16, 0, 0, 172, 31, 255, 255};
    unsigned char ip_p3[8] = {192, 168, 0, 0, 192, 168, 255, 255};
    //A、B、C、D、E类IP统计结果
    int res[5] = {0};
    //错误IP统计结果,私有IP统计结果
    int errorIP = 0, privateIP = 0;
    //输入字符串
    char str[33] = {"\0"};
    int ip[8] = {0}, temp[3] = {0};
    int i = 0, j = 1;
    //特殊标识在字符串中的位置 第一个恒为0
    int pflags[9] = {-1};
    //~字符在字符串中的位置
    int ptilde = 0;
    unsigned int k = 0;
    while (scanf("%s", str) != EOF)
    {
        while (str[i] != '\0')
        {
            if (str[i] == '.' || str[i] == '~')
            {
                if (i - pflags[j - 1] > 4 || i - pflags[j - 1] <= 1)
                    goto perror;
                pflags[j] = i;
                j++;
                if (j > 8)
                    goto perror;
                if (str[i] == '~')
                {
                    //只能有一个~字符 必须为第四个标识位(第一个标识位为0) 最小值为5 最大值为15
                    if (ptilde != 0 || j != 5 || i < 5 || i > 15)
                        goto perror;
                    ptilde = i;
                }
            }
            else if (str[i] < '0' || str[i] > '9')
                goto perror;
            i++;
            //判断长度超过32个字符(含结尾\0字符)为非法IP
            if (i > 32)
                goto perror;
        }
        pflags[8] = i;
        //判断长度小于16个字符(含结尾\0字符)为非法IP
        if (i < 15)
            goto perror;
        //转义IP地址，从字符串到整型
        //eg: 192.168.100.100~192.168.255.255
        //eg: 0-3-7-11-15-19-23-27
        for (i = 0; i < 8; i++)
        {
            temp[0] = temp[1] = temp[2] = 0;
            k = 2;
            for (j = pflags[i + 1] - 1; j > pflags[i]; j--)
            {
                temp[k] = str[j] - '0';
                k--;
            }
            ip[i] = temp[0] * 100 + temp[1] * 10 + temp[2];
            if (ip[i] > 255)
                goto perror;
        }
        //输出IP+Mask
        printf("%d.%d.%d.%d~%d.%d.%d.%d \n", ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]);
        //判定ip地址
        //忽略【0.*.*.*】和【127.*.*.*】IP地址
        if (ip[0] == 0 || ip[0] == 127)
            goto next;
        //验证子网掩码是否合法
        k = (ip[4] << 24) | (ip[5] << 16) | (ip[6] << 8) | ip[7];
        //全0或全1为非法
        if (k == 0 || k + 1 == 0)
            goto perror;
        if ((k | (k - 1)) + 1 != 0)
            goto perror;
        //验证IP地址种类
        //A类
        if (ip[0] < 10)
        {
            res[0]++;
        }
        else if (ip[0] == 10)
        {
            res[0]++;
            privateIP++;
        }
        else if (ip[0] <= 126)
        {
            res[0]++;
        }
        //B类
        else if (ip[0] < 172 || (ip[0] == 172 && ip[1] < 16))
        {
            res[1]++;
        }
        else if (ip[0] == 172 && ip[1] >= 16 && ip[1] <= 31)
        {
            res[1]++;
            privateIP++;
        }
        else if (ip[0] <= 191)
        {
            res[1]++;
        }
        //C类
        else if (ip[0] == 192 && ip[1] < 168)
        {
            res[2]++;
        }
        else if (ip[0] == 192 && ip[1] == 168)
        {
            res[2]++;
            privateIP++;
        }
        else if (ip[0] <= 233)
        {
            res[2]++;
        }
        //D类
        else if (ip[0] <= 239)
        {
            res[3]++;
        }
        //E类
        else
        {
            res[4]++;
        }
        goto next;
    perror:
        errorIP++;
        //printf("Error IP\n");
    next:
        str[0] = '\0';
        ip[0] = 0;
        ip[1] = 0;
        ip[2] = 0;
        ip[3] = 0;
        ip[4] = 0;
        ip[5] = 0;
        ip[6] = 0;
        ip[7] = 0;
        pflags[1] = 0;
        pflags[2] = 0;
        pflags[3] = 0;
        pflags[4] = 0;
        pflags[5] = 0;
        pflags[6] = 0;
        ptilde = 0;
        i = 0;
        j = 1;
    }
    printf("%d %d %d %d %d %d %d\n", res[0], res[1], res[2], res[3], res[4], errorIP, privateIP);
    return 0;
}

/*
HJ19 简单错误记录
描述
开发一个简单错误记录功能小模块，能够记录出错的代码所在的文件名称和行号。
处理：
1、 记录最多8条错误记录，循环记录，最后只用输出最后出现的八条错误记录。对相同的错误记录只记录一条，但是错误计数增加。最后一个斜杠后面的带后缀名的部分（保留最后16位）和行号完全匹配的记录才做算是“相同”的错误记录。
2、 超过16个字符的文件名称，只记录文件的最后有效16个字符；
3、 输入的文件可能带路径，记录文件名称不能带路径。也就是说，哪怕不同路径下的文件，如果它们的名字的后16个字符相同，也被视为相同的错误记录
4、循环记录时，只以第一次出现的顺序为准，后面重复的不会更新它的出现时间，仍以第一次为准
数据范围：错误记录数量满足  ，每条记录长度满足 
输入描述：
每组只包含一个测试用例。一个测试用例包含一行或多行字符串。每行包括带路径文件名称，行号，以空格隔开。
输出描述：
将所有的记录统计并将结果输出，格式：文件名 代码行数 数目，一个空格隔开
*/
#include <stdlib.h>
#include <string.h>

int main_SampleErrorRecord()
{
    char *paths[100] = {NULL};
    int lines[100] = {0};
    int reps[100] = {0};
    char s[102] = {'\0'};
    int k = 0, i = 0,s2=0;
    int ll = 0, mm = 0,loop =0;
    while (scanf("%s %d", s, &s2) != EOF)
    {
        int len = strlen(s);
        i = ll = mm = 0;
        for (i = len - 1; i >= 0 && ll < 15; i--)
        {
            if (s[i] == '\\')
            {
                i=i+1;
                break;
            }
            else
                ll++;
        }            
        if (s[i] == '\\')
           i=i+1;
        mm = i;
        ll = 0;
        for (int j = 0; j < 100; j++)
        {
            int t = 0;
            while (paths[j] != NULL && paths[j][t] != '\0' && paths[j][t] == s[mm + t])
            {
                t++;
            }
            if (t != 0 && t == strlen(paths[j]))
            {
                if(lines[j]==s2)
                {
                    reps[j]++;
                    goto pend;
                }
            }
        }
        if (paths[k] != NULL)
        {
            free(paths[k]);
            lines[k]=0;
            reps[k] = 0;
        }
        ll = len - i + 1;
        paths[k] = (char *)malloc(sizeof(char) * ll);
        for (int j = 0; j < ll; j++, i++)
            paths[k][j] = s[i];
        lines[k] = s2;
        reps[k]++;
        k++;
    pend:
        i= 0;
    }
    if(k-8<0)
        i = 0;
    else 
        i = k-8;
    for (; i < k; i++)
    {
        if (paths[i] != NULL)
            printf("%s %d %d\n", paths[i],lines[i], reps[i]);
    }
    return 0;
}

int main()
{
    // main4();
    // main_IP();
    main_SampleErrorRecord();
}
